package com.coastline.fruit.common.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES加密工具类
 * AES，全称为“Advanced Encryption Standard”，中文名“高级加密标准”，是一种对称加密算法。
 * AES加密解密的过程中，密钥长度越长，加密强度越大，但是加密解密速度越慢。
 * 加密特点：1.密钥长度可变；2.加密解密速度快；3.适合对大量数据进行加密解密。
 * 应用场景：1.文件加密；2.数据传输加密；3.数据库加密。
 * 步骤：1.生成密钥；2.加密；3.解密。
 * 优点：1.加密解密速度快；2.适合对大量数据进行加密解密。
 * 缺点：1.密钥管理不方便；2.适合对大量数据进行加密解密。
 * 安全性：1.密钥长度可变；2.加密解密速度快。
 *
 * @author Coastline
 * @date 2025/1/8 21:59
 */
public class AESUtil {
    private static final String KEY_AES = "AES";  // 算法

    private static final int KEY_SIZE = 128;  // 密钥长度（位）

    /**
     * 生成随机AES密钥
     *
     * @return 随机生成的AES密钥
     * @throws NoSuchAlgorithmException
     */
    public static String generateRandomKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGen = KeyGenerator.getInstance(KEY_AES);
        keyGen.init(KEY_SIZE, new SecureRandom()); // AES密钥长度
        SecretKey secretKey = keyGen.generateKey();
        return byte2hex(secretKey.getEncoded());
    }

    /**
     * 加密
     *
     * @param src    需要加密的内容
     * @param keyHex 十六进制表示的加密密钥
     * @return 加密后的内容
     * @throws Exception
     */
    public static String encrypt(String src, String keyHex) throws Exception {
        if (isValidKey(keyHex)) {
            throw new Exception("key不满足条件");
        }
        byte[] raw = hex2byte(keyHex);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_AES);
        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(src.getBytes());
        return byte2hex(encrypted);
    }

    /**
     * 解密
     *
     * @param src    需要解密的内容
     * @param keyHex 十六进制表示的解密密钥
     * @return 解密后的内容
     * @throws Exception
     */
    public static String decrypt(String src, String keyHex) throws Exception {
        if (isValidKey(keyHex)) {
            throw new Exception("key不满足条件");
        }
        byte[] raw = hex2byte(keyHex);
        SecretKeySpec secretKeySpec = new SecretKeySpec(raw, KEY_AES);
        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] encrypted1 = hex2byte(src);
        byte[] original = cipher.doFinal(encrypted1);
        return new String(original);
    }

    /**
     * 验证密钥是否有效
     *
     * @param keyHex 十六进制表示的密钥
     * @return 是否有效
     */
    private static boolean isValidKey(String keyHex) {
        return keyHex == null || keyHex.length() != (KEY_SIZE / 4);
    }

    /**
     * 将16进制转换为二进制
     *
     * @param strhex 16进制字符串
     * @return 二进制字节数组
     */
    public static byte[] hex2byte(String strhex) {
        if (strhex == null) {
            return null;
        }
        int l = strhex.length();
        if (l % 2 == 1) {
            return null;
        }
        byte[] b = new byte[l / 2];
        for (int i = 0; i != l / 2; i++) {
            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2), 16);
        }
        return b;
    }

    /**
     * 将二进制转换为16进制
     *
     * @param b 二进制字节数组
     * @return 16进制字符串
     */
    public static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (byte value : b) {
            stmp = Integer.toHexString(value & 0XFF);
            if (stmp.length() == 1) {
                hs.append("0").append(stmp);
            } else {
                hs.append(stmp);
            }
        }
        return hs.toString().toUpperCase();
    }
}
